/*
 * Copyright (c) 2023 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include "interface/i_accessor.h"
#include <algorithm>
#include <mc/log.h>
#include <vector>

namespace dev {

void IAccessor::init_accessor_signal() {
    // 定义读取属性的getter，每次访问时从Chip读取最新值
    auto property_read = [this]() -> uint64_t {
        try {
            // 每次都重新获取Chip引用，确保使用最新值
            auto  ref_chip = Chip.get_value();
            auto* ref_obj  = ref_chip.as<mc::engine::ref_object*>();
            if (ref_obj == nullptr) {
                MC_THROW(mc::invalid_op_exception, "Chip object reference is invalid");
            }

            // 根据Type参数决定调用BitIORead还是BlockIORead
            uint8_t type = Type.get_value().as<uint8_t>();
            if (type == 0) {
                // 使用BitIORead方法，参数为offset, size, mask
                mc::variants args   = {Offset.get_value(), Size.get_value(), Mask.get_value()};
                auto         result = ref_obj->invoke("BitIORead", args);

                // 检查返回结果的有效性
                if (result.is_null()) {
                    MC_THROW(mc::invalid_op_exception, "BitIORead returned null");
                }
                try {
                    std::vector<uint8_t> read_data = result.as<std::vector<uint8_t>>();
                    if (read_data.empty()) {
                        MC_THROW(mc::invalid_op_exception, "BitIORead returned empty data");
                    }

                    uint32_t             mask_value   = 0;
                    uint32_t             current_byte = 0;
                    std::vector<uint8_t> byte_read_buf(4, 0);

                    size_t size = std::min(read_data.size(), sizeof(uint64_t));

                    // 缓存 mask 值，避免重复调用 get_value()
                    const uint32_t mask = Mask.get_value().as<uint32_t>();

                    for (uint32_t i = 0; i < 8 * size; i++) {
                        if ((mask >> i) & 0x01) {
                            current_byte = read_data[size - (i / 8) - 1];
                            byte_read_buf[mask_value / 8] |=
                                (((current_byte >> (i % 8)) & 0x01) << (mask_value % 8));
                            mask_value++;
                        }
                    }

                    uint64_t     value      = 0;
                    const size_t final_size = std::min(byte_read_buf.size(), sizeof(uint64_t));
                    for (size_t i = 0; i < final_size; ++i) {
                        value |= (static_cast<uint64_t>(byte_read_buf[i]) << (i * 8));
                    }
                    return value;
                } catch (const std::exception& e) {
                    MC_THROW(mc::invalid_op_exception, "BitIORead data conversion failed: ${error}",
                             ("error", e.what()));
                }
            } else {
                // 使用BlockIORead方法，参数为offset, size
                mc::variants args   = {Offset.get_value(), Size.get_value()};
                auto         result = ref_obj->invoke("BlockIORead", args);

                // 检查返回结果的有效性
                if (result.is_null()) {
                    MC_THROW(mc::invalid_op_exception, "BlockIORead returned null");
                }

                // 提取数据，如果失败则抛出异常
                std::vector<uint8_t> read_data;
                try {
                    read_data = result.as<std::vector<uint8_t>>();
                } catch (const std::exception& e) {
                                    MC_THROW(mc::invalid_op_exception, "BlockIORead data conversion failed: ${error}",
                         ("error", e.what()));
                }

                if (read_data.empty()) {
                    MC_THROW(mc::invalid_op_exception, "Read data is empty");
                }

                uint64_t value = 0;
                size_t   size  = std::min(read_data.size(), sizeof(uint64_t));
                for (size_t i = 0; i < size; ++i) {
                    value |= (static_cast<uint64_t>(read_data[i]) << (i * 8));
                }

                return value;
            }
        } catch (const std::exception& e) {
            MC_THROW(mc::invalid_op_exception, "Failed to read property: ${error}", ("error", e.what()));
        }
    };

    // 定义写入属性的setter，写入成功才允许属性更新
    auto property_write = [this](uint64_t value) -> bool {
        try {
            // 每次都重新获取Chip引用，确保使用最新值
            auto  ref_chip = Chip.get_value();
            auto* ref_obj  = ref_chip.as<mc::engine::ref_object*>();

            if (ref_obj == nullptr) {
                elog("Error: Chip object reference is invalid");
                return false; // 写入失败，不更新属性
            }

            // 根据Type参数决定调用BitIOWrite还是BlockIOWrite
            uint8_t type = Type.get_value().as<uint8_t>();
            if (type == 0) {
                uint8_t              size = Size.get_value().as<uint8_t>();
                std::vector<uint8_t> write_data;
                write_data.reserve(size);

                for (uint8_t i = 0; i < size; ++i) {
                    write_data.push_back(static_cast<uint8_t>((value >> (i * 8)) & 0xFF));
                }
                // 使用BitIOWrite方法，参数为offset, size, mask, value
                mc::variants args = {Offset.get_value(), size, Mask.get_value(), write_data};
                ref_obj->invoke("BitIOWrite", args);
                return true; // 写入成功，允许属性更新
            } else {
                // 使用BlockIOWrite方法，参数为offset, write_data
                // 将uint64_t转换为字节数组（小端序）
                uint8_t              size = Size.get_value().as<uint8_t>();
                std::vector<uint8_t> write_data;
                write_data.reserve(size);

                for (uint8_t i = 0; i < size; ++i) {
                    write_data.push_back(static_cast<uint8_t>((value >> (i * 8)) & 0xFF));
                }

                mc::variants args = {Offset.get_value(), write_data};
                ref_obj->invoke("BlockIOWrite", args);
                return true; // 写入成功，允许属性更新
            }
        } catch (const std::exception& e) {
            elog("Property write exception: ${exception}", ("exception", e.what()));
            return false; // 写入失败，不更新属性
        }
    };

    Value.make_outsider_getter_setter(property_read, property_write);
}

} // namespace dev

MC_REFLECT(dev::IAccessor)
